package cn.yueranzs.config;

import cn.yueranzs.login.service.impl.JwtAuthenticationTokenFilter;
import cn.yueranzs.login.service.impl.LoginAuthenticationProvider;
import cn.yueranzs.login.service.impl.LoginUserDetails;
import cn.yueranzs.response.HttpResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetails;

import javax.servlet.http.HttpServletRequest;


/**
 * @author yueranzs
 * @date 2021/11/22 13:56
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private LoginAuthenticationProvider loginAuthenticationProvider;
    @Autowired
    private LoginUserDetails loginUserDetails;
    @Autowired
    private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource;

    /**
     * SpringSecurity5.X要求必须指定密码加密方式，否则会在请求认证的时候报错
     * 同样的，如果指定了加密方式，就必须您的密码在数据库中存储的是加密后的，才能比对成功
     * @return
     */
    @Bean
    protected BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    protected JwtAuthenticationTokenFilter authenticationTokenFilter() throws Exception{
        return new JwtAuthenticationTokenFilter();
    }

    /**
     * 角色继承
     * admin > user
     * @return
     */
    @Bean
    RoleHierarchy roleHierarchy(){
        RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
        hierarchy.setHierarchy("ROLE_admin > ROLE_user");
        return hierarchy;
    }

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers("/js/**", "/css/**","/images/**");
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //将自定义的Provider装配到Builder
        auth.authenticationProvider(loginAuthenticationProvider);
        //将自定义的loginserviceimpl装配到builder
        auth.userDetailsService(loginUserDetails).passwordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                return rawPassword.toString();
            }

            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return encodedPassword.equals(rawPassword.toString());
            }
        });
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/doc.html").permitAll()
            .antMatchers("/webjars/**").permitAll()
            .antMatchers("/swagger-resources/**").permitAll()
            .antMatchers("/v2/*").permitAll()
            .antMatchers("/login/getRandomCode","/login/getUserAvatar").permitAll()
//            .antMatchers("/admin/**").hasRole("admin")
//            .antMatchers("/user/**").hasRole("user")
            .anyRequest().authenticated()
            .and()
            .formLogin()
            //登录页
            .loginPage("/login.html")
            //登录请求接口，如果url为空也会默认将loginPage的值赋值给url
            .loginProcessingUrl("/login/loginUser")
            //设置登录参数别名
            .usernameParameter("username")
            .passwordParameter("password")
            .successHandler(HttpResponseResult::loginSuccess)
            .failureHandler((req, resp, e) -> HttpResponseResult.loginError(resp,e))
            .authenticationDetailsSource(authenticationDetailsSource)
            .permitAll()
            .and()
            .csrf().disable()
            .exceptionHandling()
            .authenticationEntryPoint((req, resp, auth) -> HttpResponseResult.noProof(resp))
            .accessDeniedHandler(HttpResponseResult::insufficientPermissions)
            .and()
            //设置无状态的连接,即不创建session
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            //退出登录
            /*.logout()
            .logoutUrl("/login/logout")
            .logoutSuccessHandler(HttpResponseResult::logout)
            .permitAll()
            .and()*/
        ;

        http.addFilterBefore(authenticationTokenFilter(),UsernamePasswordAuthenticationFilter.class);
        //禁止页面缓存
        http.headers().cacheControl();
    }

}
